package asteroids.model.programs.statements.ProgramStatements;

import java.util.ArrayList;
import java.util.List;

import asteroids.model.programs.Program;
import asteroids.model.programs.expressions.Expression;
import asteroids.model.programs.expressions.BasicExpressions.BooleanLiteral;
import asteroids.model.programs.statements.ActionStatement;
import asteroids.model.programs.statements.ProgramStatement;
import asteroids.model.programs.statements.Statement;

/**
 * A class representing a Sequence-statement, this class is a subclass of the
 * Statement-class.
 * 
 * A Sequence-statement is a sequence of statements that will be executed one
 * after another. A Sequence-statement can function as e.g. the body of an If-
 * or While-Statement.
 * 
 * @author Michiel De Cuyper
 * @version 09.05
 * 
 */
public class SequenceStatement extends ProgramStatement {

	/**
	 * Constructor for a SequenceStatement
	 * 
	 * 
	 * @param line
	 *            The line on which this if-statement is found Gets passed to
	 *            the Statement-class
	 * @param column
	 *            The column in which this if-statement is found Gets passed to
	 *            the Statement-class
	 * @param statements
	 *            A list of statements, which contains the statements that have
	 *            to be executed
	 */
	public SequenceStatement(int line, int column, List<Statement> statements) {
		super(line, column);
		this.setStatements(statements);
	}

	/**
	 * Executes this Sequence-statement, by executing all statements in its
	 * list.
	 * 
	 * @effect ... | for each Statement s in this.getStatements | s.execute();
	 */
	public SequenceStatement execute(int amount) {
		if (statements.isEmpty()) return getNextStart(); //when the end of the loop is reached, return to beginning
		
		Statement firstStatement = statements.get(0);
		SequenceStatement secondStatement = (SequenceStatement) statements.get(1);
		
		//While statement
		if(firstStatement instanceof WhileStatement) {
			SequenceStatement whileBody = ((WhileStatement)firstStatement).getBody();
			whileBody.setNextStart(this);
			Expression whileCondition = ((WhileStatement)firstStatement).getCondition();
			
			if(((BooleanLiteral)whileCondition.getResult()).getValue()){
				return whileBody.execute(amount);
			}
		}
		
		//If Statement
		if(firstStatement instanceof IfStatement){
			Expression ifCondition = ((IfStatement)firstStatement).getCondition();
			if(((BooleanLiteral)ifCondition.getResult()).getValue()){
				SequenceStatement thenBody = (SequenceStatement) ((IfStatement)firstStatement).getThen();
				thenBody.setNextStart(secondStatement);
				return thenBody.execute(amount);
			}
			else{
				SequenceStatement otherwiseBody = (SequenceStatement) ((IfStatement)firstStatement).getOtherwise();
				otherwiseBody.setNextStart(secondStatement);
				return otherwiseBody.execute(amount);
			}
		}
		
		
		if (firstStatement instanceof ActionStatement) amount -= 1;
		firstStatement.execute();

		if (amount == 0) return secondStatement;
		return secondStatement.execute(amount);
	}

	/**
	 * Sets the statements of this sequence to a given list of statements
	 * 
	 * @param statements
	 *            The list of statements for this sequence
	 * @post ... | (new this).getStatements() == statements
	 */
	public void setStatements(List<Statement> statements) {
		this.statements = statements;
	}

	/**
	 * Returns the statements of this sequence
	 * 
	 * @return ... | return this.statements
	 */
	public List<Statement> getStatements() {
		return this.statements;
	}

	@Override
	public void setProgram(Program program) {
		super.setProgram(program);
		for (Statement s : statements) {
			s.setProgram(program);
		}
	}

	/**
	 * A list-variable storing all statements in this sequence
	 */
	private List<Statement> statements;

	@Override
	public void execute() {
		execute(1);
	}

	@Override
	public Expression getExpression() {
		return null;
	}
	
	@Override
	public void setNextStart(SequenceStatement start){
		super.setNextStart(start);
		for(Statement statement : statements){
				statement.setNextStart(start);
			}
		
	}

	@Override
	public String typeCheckStatement(String errorMessage) {
		if(statements.isEmpty()) return errorMessage;
		
		String newErrorMessage = getStatements().get(0).typeCheckStatement(errorMessage);
		String addErrorMessage = getStatements().get(1).typeCheckStatement(errorMessage);
		
		
		if(newErrorMessage == null ) {
			newErrorMessage = addErrorMessage;
		}
		else if(newErrorMessage != null && addErrorMessage != null){
			newErrorMessage  += addErrorMessage;
		}
		
		return newErrorMessage;
	}
	
	public ArrayList<Statement> convertToArrayList() {
        ArrayList<Statement> toReturn = new ArrayList<Statement>();
        SequenceStatement s = (SequenceStatement)statements.get(1);
        toReturn.add(statements.get(0));
        Boolean loop = true;
        while(loop) {
                try {
                       Statement toAdd =  s.getStatements().get(0);
                       toReturn.add(toAdd);
                       s = (SequenceStatement) s.getStatements().get(1);
                        
                } catch(Exception e) {
                        loop = false;
                }
        }
        
        return toReturn;
}

}
